#include "Gfx.h"

Gfx *Gfx::instance_ = NULL;

Gfx::
Gfx () 
	: ldisplay(NULL), screen(NULL), screen_buffer(NULL) {
}

Gfx::
~Gfx () {
	/* If there was a layered display,
	   free it (there should be one !) */
	if ( ldisplay ) {
		SDLayer_FreeLayeredDisplay (ldisplay);
		ldisplay = NULL;
	}

	/* If a screen buffer was initialized, free it
	   (there should be one !) */
	if ( screen_buffer ) {
		SDL_FreeSurface (screen_buffer);
		screen_buffer = NULL;
	}

	/** *NEVER* free the screen surface */
}

int Gfx::
__initSDL (void) {
	int state;

	state = SDL_Init (SDL_INIT_VIDEO);

	if ( state == -1 )
	{
	fprintf (stderr,
	"Gfx: %s: cannot initialize SDL.\n"
	"         (sdl report: %s)",
	__func__, SDL_GetError());
	}

	atexit ( SDL_Quit );
	return state;
}

int Gfx::
__initVideoMode (int width, int height, int bpp, Uint32 flag) {
	Uint32 sdl_flags;

	if ( (flag != GFX_FULLSCREEN) && (flag != GFX_WINDOWED) )
	{
	fprintf (stderr,
	"Gfx: %s: Unsupported flag: %lu\n"
	"         Possible values are: GFX_WINDOWED, GFX_FULLSCREEN\n",
	__func__, flag);
	return -1;
	}

	if ( flag & GFX_FULLSCREEN ) {
		sdl_flags |= SDL_FULLSCREEN;
	}

	if ( (screen = SDL_SetVideoMode(width, height, bpp, sdl_flags)) == NULL ) {
		/* Maybe your os didn't like the fullscreen ? */
		if ( sdl_flags & SDL_FULLSCREEN ) {
			fprintf (stdout,
			"Gfx: %s: Retrying in windowed mode\n", __func__);
			sdl_flags &= ~SDL_FULLSCREEN;
		
			screen = SDL_SetVideoMode(width, height, bpp, sdl_flags);
		}

		if (screen == NULL) {
			/* We don't investigate further: it's over */
			fprintf (stderr,
			"Gfx: %s: Cannot setup a %dx%d@%d display, SDL_ANYFORMAT\n",
			__func__, width, height, bpp);
			return -1;
		}		
	}

	/* Finally succeeded. Check whether the depth was the requested one */
	if ( screen->format->BitsPerPixel != bpp ) {
		/* If not, report it */
		fprintf (stdout,
		"Gfx: %s: using %d bpp instead of %d bpp\n",
		__func__, screen->format->BitsPerPixel, bpp);
	}

	/* Allocate memory for a screen buffer */
	SDL_Surface * surf  = NULL;
	Uint32 buffer_flags = screen->flags; // Use the same flags as the screen so
													 // that if the screen is in SW/HW
													 // memory, the buffer is in the same
													 // memory area for performance
	buffer_flags &= ~SDL_FULLSCREEN;		 // Remove the fullscreen flag
	surf = SDL_CreateRGBSurface (buffer_flags, screen->w, screen->h, screen->format->BitsPerPixel,
					screen->format->Rmask, screen->format->Gmask,
					screen->format->Bmask, screen->format->Amask);
	
	if ( surf == NULL ) {
	fprintf (stderr,
	"Gfx: %s: Cannot allocate memory for the screen buffer.\n",
	__func__);
	return -1;
	}

	screen_buffer = SDL_DisplayFormat(surf);
	if ( screen_buffer == NULL ) {
	fprintf (stderr,
	"Gfx: %s: Cannot convert the screen buffer to the display format.\n",
	__func__);
	return -1;
	}

	SDL_FreeSurface(surf);
	
	return screen->format->BitsPerPixel;	
}

int Gfx::
init (int width, int height, int bpp, Uint32 flags) {
	// Init = Init SDL + Setup video surface
	if ( __initSDL() == -1 ) {
		return -1;
	}
	return ( __initVideoMode(width, height, bpp, flags) );
}

void Gfx::
saveScreen (void) {
	SDL_Rect rect;

	rect.x = 0;
	rect.y = 0;
	rect.w = screen->w;
	rect.h = screen->h;

	SDL_BlitSurface (screen, &rect, screen_buffer, &rect);
}

void Gfx::
restoreScreen (void) {
	SDL_Rect rect;

	rect.x = 0;
	rect.y = 0;
	rect.w = screen->w;
	rect.h = screen->h;

	SDL_BlitSurface (screen_buffer, &rect, screen, &rect);
	/* Force update */
	SDL_UpdateRects (screen, 1, &rect);
}

void Gfx::
clearScreen (void) {
	SDL_Rect rect;

	rect.x = 0;
	rect.y = 0;
	rect.w = screen->w;
	rect.h = screen->h;

	SDL_FillRect(screen, &rect, 0);
	SDL_UpdateRects(screen, 1, &rect);
}

void Gfx::
clearAll (void) {
	SDLayer_Fill(ldisplay, 0);
	SDLayer_Update(ldisplay);
}

void Gfx::toggleFullScreen(void) {
	SDLayer_ToggleFullScreen(ldisplay);
	/* Mark a delay */
	SDL_Delay(1700);
}

void Gfx::
update (void) {
	SDLayer_Update(ldisplay);
}

SDL_Surface *
Gfx::
createSurface (int w, int h, bool HW) {
  SDL_Surface *tmp = SDL_CreateRGBSurface (
    ((HW) ? (SDL_HWSURFACE) : (SDL_SWSURFACE)),
    w, h, 32, 0, 0, 0, 0
  );
  SDL_Surface *surf = SDL_DisplayFormat(tmp);
  SDL_FreeSurface(tmp);
  return surf;
}

